Option Explicit

' 克隆一个 Map 对象
' @param src 需要克隆的 map 对象
' @return 克隆后的 map
'         基础类型数据将会进行数据复制
'         对象数据类型只能复制引用
Public Function cloneMap(ByRef src As Object) As Object
    ' 1. 检查参数
    If src Is Nothing Then
        ' return null
        Exit Function
    End If

    ' 1. 创建新的 Map
    Dim result As Object
    If TypeOf src Is SimpleMap Then
        Set result = New SimpleMap
        Dim k1 As Variant
        For Each k1 In src.Keys
            result.Add k1 & "", src.Item(k1 & "")
        Next
    Else
        Set result = UtilsCreateSysObj.createMap
        Dim k2 As Variant
        For Each k2 In src.Keys
            result.Add k2, src.Item(k2)
        Next
    End If

    Set cloneMap = result
End Function

' 合并两个 map，将 desc 中的内容合并到 src
' 这里只能处理对象类型的 value
' @oaram src 保存数据的 map
' @oaram desc 被合并的 map
' @optional-param needMergeEmptyVal 是否需要合并 value 是 Nothing 的 key-value。默认 = True
Public Sub mergeMapForObjectVal(ByRef src As Object, ByRef desc As Object, Optional ByRef needMergeEmptyVal As Boolean = True)
    ' 1. 检查参数
    ' 1.1 如果参数 src + desc 中的任意一个是 Nothing，将不会执行合并操作
    If src Is Nothing Then
        Exit Sub
    End If

    If desc Is Nothing Then
        Exit Sub
    End If

    ' 1.2 如果参数 desc 的长度是 0 ，则立刻结束
    If desc.Count = 0 Then
        Exit Sub
    End If

    '2. 按照 needMergeEmptyVal 来执行合并
    Dim k As Variant
    If needMergeEmptyVal Then
        ' 需要合并空值
        For Each k In desc.Keys
            If src.Exists(k) Then
                src.Remove k
            End If

            src.Add k, desc.Item(k)
        Next
    Else
        ' 需要跳过空值
        Dim v As Variant
        For Each k In desc.Keys
            Set v = desc.Item(k)

            If v Is Nothing Then
                Goto for2Continue
            End If

            If src.Exists(k) Then
                src.Remove k
            End If

            src.Add k, v
for2Continue:
        Next
    End If
End Sub

' 合并两个 map，将 desc 中的内容合并到 src
' 这里只能处理基础数据类型的 value
' @oaram src 保存数据的 map
' @oaram desc 被合并的 map
' @optional-param needMergeIgnoredVal 是否合并被忽略的 val 值，默认为 = True
' @optional-param ignoredVal 需要被忽略的 val 值，默认为 = Empty
Public Sub mergeMapForPrimitiveVal( _
    ByRef src As Object, ByRef desc As Object, _
    Optional ByRef needMergeIgnoredVal As Boolean = True, Optional ByRef ignoredVal As Variant = Empty)
    ' 1. 检查参数
    ' 1.1 如果参数 src + desc 中的任意一个是 Nothing，将不会执行合并操作
    If src Is Nothing Then
        Exit Sub
    End If

    If desc Is Nothing Then
        Exit Sub
    End If

    ' 1.2 如果参数 desc 的长度是 0 ，则立刻结束
    If desc.Count = 0 Then
        Exit Sub
    End If

    '2. 按照 needMergeEmptyVal 来执行合并
    Dim k As Variant
    If needMergeIgnoredVal Then
        ' 合并需要忽略的值
        For Each k In desc.Keys
            If src.Exists(k) Then
                src.Remove k
            End If

            src.Add k, desc.Item(k)
        Next
    Else
        ' 跳过需要忽略的值
        Dim v As Variant
        For Each k In desc.Keys
            v = desc.Item(k)

            If v = ignoredVal Then
                Goto for2Continue
            End If

            If src.Exists(k) Then
                src.Remove k
            End If

            src.Add k, v
for2Continue:
        Next
    End If
End Sub

' 以 value 为 key，将映射 [value:value] 保存到 map 中
'
' @param src 原始 map
' @optional-param needCover 如果 value 和某个 key 相同，是否需要覆盖。默认=True
Public Sub addMapValValToMap(ByRef src As Object, Optional needCover = True)
    ' 1. 检查参数
    If src Is Nothing Then
        Exit Sub
    End If

    If src.Count = 0 Then
        Exit Sub
    End If

    ' 2. 开始向 Map 中添加 [value:value] 映射
    Dim v As Variant
    If needCover Then
        ' 某个 key 和 value 发生重复时，覆盖
        For Each v In src.Items
            If src.Exists(v) Then
                src.Remove v
            End If

            src.Add v, v
        Next
    Else
        ' 某个 key 和 value 发生重复时，跳过
        For Each v In src.Items
            If Not src.Exists(v) Then
                src.Add v, v
            End If
        Next
    End If
End Sub
